package com.stellar.core.sender.impl;


import com.aliyun.auth.credentials.Credential;
import com.aliyun.auth.credentials.provider.StaticCredentialProvider;
import com.aliyun.sdk.service.dysmsapi20170525.AsyncClient;
import com.aliyun.sdk.service.dysmsapi20170525.models.SendSmsRequest;
import com.aliyun.sdk.service.dysmsapi20170525.models.SendSmsResponse;
import com.stellar.config.properties.AuthSmsProperties;
import com.stellar.config.properties.AuthSmsSecurityProperties;
import com.stellar.core.sender.SendRecord;
import com.stellar.core.sender.SmsCodeSender;
import com.stellar.core.service.cache.SmsCacheService;
import com.stellar.web.core.exception.SmsSendException;
import darabonba.core.client.ClientOverrideConfiguration;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @Author: Jqchan_
 * @Description: 短信发送服务实现类 - 验证码时效性由业务方维护
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class SmsServiceImpl implements SmsCodeSender {

    private final AuthSmsProperties smsProperties;

    private final AuthSmsSecurityProperties authSmsSecurityProperties;

    private final SmsCacheService cacheService;


    @Override
    public boolean send(String phoneNumber, Map<String, String> templateParam) {
        // 获取客户端IP
        String clientIp = getClientIp();

        // 获取分布式锁
        Lock lock = cacheService.getLock(phoneNumber);

        try {
            // 尝试获取锁，设置超时时间防止死锁
            if (lock.tryLock(authSmsSecurityProperties.getLockTimeoutMs(), TimeUnit.MILLISECONDS)) {
                try {
                    // 检查手机号发送频率
                    if (!checkPhoneFrequency(phoneNumber)) {
                        log.warn("手机号 {} 发送频率过高，请求被拒绝", phoneNumber);
                        throw new SmsSendException(String.format("手机号 %s 发送频率过高，请求被拒绝", phoneNumber));
                    }

                    // 检查IP发送频率
                    if (!checkIpFrequency(clientIp)) {
                        log.warn("IP {} 发送频率过高，请求被拒绝", clientIp);
                        throw new SmsSendException(String.format("IP %s 访问过快，请求被拒绝", clientIp));
                    }

                    // 发送短信
                    boolean sendResult = actualSendSms(phoneNumber, templateParam);

                    // 发送成功后更新记录
                    if (sendResult) {
                        updateSendRecords(phoneNumber, clientIp);
                        log.info("短信发送成功，手机号: {}, IP: {}", phoneNumber, clientIp);
                    }
                    return sendResult;
                } finally {
                    lock.unlock();
                }
            } else {
                log.warn("手机号 {} 请求过于频繁，系统繁忙", phoneNumber);
                throw new SmsSendException(String.format("手机号 %s 请求过于频繁，系统繁忙", phoneNumber));
            }
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            log.error("短信发送线程被中断", e);
            return false;
        }
    }

    private String convertToJson(Map<String, String> templateParam) {
        if (templateParam == null || templateParam.isEmpty()) {
            return "{}";
        }
        StringBuilder sb = new StringBuilder("{");
        for (Map.Entry<String, String> entry : templateParam.entrySet()) {
            sb.append("\"").append(entry.getKey()).append("\":\"")
                    .append(entry.getValue()).append("\",");
        }
        sb.deleteCharAt(sb.length() - 1);
        sb.append("}");
        return sb.toString();
    }

    /**
     * 实际发送短信方法
     */
    private boolean actualSendSms(String phoneNumber, Map<String, String> templateParam) {
        try {
            // 创建认证提供者
            StaticCredentialProvider provider = StaticCredentialProvider.create(
                    Credential.builder()
                            .accessKeyId(smsProperties.getAccessKeyId())
                            .accessKeySecret(smsProperties.getAccessKeySecret())
                            .build()
            );

            // 创建异步客户端
            try (AsyncClient client = AsyncClient.builder()
                    .credentialsProvider(provider)
                    .overrideConfiguration(
                            ClientOverrideConfiguration.create()
                                    .setEndpointOverride(smsProperties.getEndpoint())
                    )
                    .build()) {

                // 构建请求
                SendSmsRequest request = SendSmsRequest.builder()
                        .phoneNumbers(phoneNumber)
                        .signName(smsProperties.getSignName())
                        .templateCode(smsProperties.getTemplateCode())
                        .templateParam(convertToJson(templateParam))
                        .build();

                // 发送短信并获取响应
                CompletableFuture<SendSmsResponse> responseFuture = client.sendSms(request);
                SendSmsResponse response = responseFuture.join();

                // 判断发送结果
                return "OK".equalsIgnoreCase(response.getBody().getCode());
            }
        } catch (Exception e) {
            log.error("短信发送失败: {}", e.getMessage(), e);
            throw new SmsSendException("短信发送失败");
        }
    }

    /**
     * 检查手机号发送频率
     */
    private boolean checkPhoneFrequency(String phoneNumber) {
        SendRecord record = cacheService.getPhoneRecord(phoneNumber);
        if (record == null) {
            return true; // 无记录，允许发送
        }

        long currentTime = System.currentTimeMillis();
        long oneMinuteAgo = currentTime - TimeUnit.MINUTES.toMillis(1);
        long oneHourAgo = currentTime - TimeUnit.HOURS.toMillis(1);
        long oneDayAgo = currentTime - TimeUnit.DAYS.toMillis(1);

        // 检查1分钟内发送次数
        if (record.getMinuteCount() >= authSmsSecurityProperties.getMaxPerMinute()
                && record.getLastMinuteTimestamp() > oneMinuteAgo) {
            return false;
        }

        // 检查1小时内发送次数
        if (record.getHourCount() >= authSmsSecurityProperties.getMaxPerHour()
                && record.getLastHourTimestamp() > oneHourAgo) {
            return false;
        }

        // 检查24小时内发送次数
        if (record.getDayCount() >= authSmsSecurityProperties.getMaxPerDay()
                && record.getLastDayTimestamp() > oneDayAgo) {
            return false;
        }

        return true;
    }

    /**
     * 检查IP发送频率
     */
    private boolean checkIpFrequency(String ip) {
        SendRecord record = cacheService.getIpRecord(ip);
        if (record == null) {
            return true; // 无记录，允许发送
        }

        long currentTime = System.currentTimeMillis();
        long oneMinuteAgo = currentTime - TimeUnit.MINUTES.toMillis(1);

        // 检查1分钟内发送次数
        if (record.getMinuteCount() >= authSmsSecurityProperties.getMaxIpPerMinute()
                && record.getLastMinuteTimestamp() > oneMinuteAgo) {
            return false;
        }

        return true;
    }

    /**
     * 更新发送记录
     */
    private void updateSendRecords(String phoneNumber, String clientIp) {
        long currentTime = System.currentTimeMillis();

        // 更新手机号记录
        cacheService.updatePhoneRecord(phoneNumber, currentTime);

        // 更新IP记录
        cacheService.updateIpRecord(clientIp, currentTime);
    }

    /**
     * 获取客户端IP
     */
    private String getClientIp() {
        try {
            HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder
                    .currentRequestAttributes()).getRequest();

            String ip = request.getHeader("X-Forwarded-For");
            if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
                ip = request.getHeader("Proxy-Client-IP");
            }
            if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
                ip = request.getHeader("WL-Proxy-Client-IP");
            }
            if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
                ip = request.getRemoteAddr();
            }
            return ip.split(",")[0]; // 防止多级代理
        } catch (Exception e) {
            log.error("获取客户端IP失败", e);
            return "0.0.0.0";
        }
    }


}
